package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.HotArticleService;
import com.heima.common.constants.article.ArticleConstants;
import com.heima.common.exception.CustException;
import com.heima.feign.AdminFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.vo.HotArticleVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.message.ArticleVisitStreamMess;
import com.heima.utils.common.DateUtils;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class HotArticleServiceImpl implements HotArticleService {

  /** 计算热点文章 */
  @Autowired ApArticleMapper apArticleMapper;

  @Autowired private RedisTemplate<String, String> redisTemplate;

  @Override
  public void computeHotArticle() {
    // 查询五天的文章
    String date =
        LocalDateTime.now().minusDays(5).format(DateTimeFormatter.ofPattern("yyyy-MM-dd 00:00:00"));
    List<ApArticle> apArticles = apArticleMapper.selectArticleByDate(date);
    if (apArticles == null) {
      CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
    }
    // 开始计算热点文章的分值
    List<HotArticleVo> hotArticleVos = computeArticleScore(apArticles);
    // 开始缓存每个频道下的分值较高的30条文章
    cacheTagToRedis(hotArticleVos);
  }

  /** /** * 重新计算文章热度 更新redis缓存 * @param mess */
  @Override
  public void updateApArticle(ArticleVisitStreamMess mess) {
    // 1查询文章
    ApArticle apArticle = apArticleMapper.selectById(mess.getArticleId());
    if (apArticle == null) {
      CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
    }

    // 修改文章的数据阅读1，点赞3， 评论5 ，收藏8
    if (mess.getView() != 0) {
      int view =
          (int)
              (apArticle.getViews() == null
                  ? mess.getView()
                  : mess.getView() + apArticle.getViews());
      apArticle.setViews(view);
    }
    if (mess.getLike() != 0) {
      int like =
          (int)
              (apArticle.getLikes() == null
                  ? mess.getLike()
                  : mess.getView() + apArticle.getViews());
      apArticle.setLikes(like);
    }
    if (mess.getComment() != 0) {
      int comment =
          (int)
              (apArticle.getComment() == 0
                  ? mess.getComment()
                  : mess.getComment() + apArticle.getComment());
      apArticle.setComment(comment);
    }
    if (mess.getCollect() != 0) {
      int collect =
          (int)
              (apArticle.getCollection() == 0
                  ? mess.getCollect()
                  : mess.getCollect() + apArticle.getCollection());
      apArticle.setCollection(collect);
    }
    apArticleMapper.updateById(apArticle);
    // 计算文章的分值
    Integer score = computeScore(apArticle);

    //如果时当天的文章*3
    String publishStr = DateUtils.dateToString(apArticle.getPublishTime());
    String nowStr = DateUtils.dateToString(new Date());
    if (publishStr.equals(nowStr)){
      score=score*3;
    }
    // 更新缓存
    updateArticleCache(apArticle, score, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + apArticle.getChannelId());

    // 更新推荐列表的缓存
    updateArticleCache(apArticle,score,ArticleConstants.HOT_ARTICLE_FIRST_PAGE+ArticleConstants.DEFAULT_TAG);

  }
  /**
   * 更新文章缓存
   * @param apArticle  当前文章
   * @param score 分数
   * @param cacheKey
   */
  private void updateArticleCache(ApArticle apArticle, Integer score, String cacheKey) {
    boolean flag = false;
    //从缓存中获取文章
    String hotArticleListJson = redisTemplate.opsForValue().get(cacheKey);
    if (StringUtils.isNotBlank(hotArticleListJson)){
      //转化成list集合
      List<HotArticleVo> hotArticleVos = JSONArray.parseArray(hotArticleListJson, HotArticleVo.class);
      for (HotArticleVo hotArticleVo : hotArticleVos) {
        //如果缓存中存在这个文章，更新它的分值
        if (hotArticleVo.getId()==apArticle.getId()){
          hotArticleVo.setScore(score);
          flag=true;
          break;
        }
      }
      if (!flag){
        HotArticleVo hotArticle = new HotArticleVo();
        BeanUtils.copyProperties(apArticle,hotArticle);
        hotArticle.setScore(score);
        hotArticleVos.add(hotArticle);
      }
      //将热点文章集合，按照降分的排序去前三十放到redis中
      hotArticleVos=hotArticleVos.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed())
                    .limit(30)
                    .collect(Collectors.toList());
      redisTemplate.opsForValue().set(cacheKey,JSON.toJSONString(hotArticleVos));
    }

  }

  @Autowired AdminFeign adminFeign;

  private void cacheTagToRedis(List<HotArticleVo> hotArticleVos) {
    // 远程调用获取频道列表
    ResponseResult responseResult = adminFeign.selectAllChannel();
    if (responseResult.getCode() == 0) {
      // 频道列表
      List<AdChannel> adChannelList =
          JSON.parseArray(JSON.toJSONString(responseResult.getData()), AdChannel.class);
      // 遍历频道，获取当前频道下的文章，放入缓存中
      for (AdChannel adChannel : adChannelList) {
        List<HotArticleVo> hotArticleList =
            hotArticleVos.stream()
                .filter(hotArticleVo -> adChannel.getId().equals(hotArticleVo.getChannelId()))
                .collect(Collectors.toList());
        // 放到缓存中
        cacheArticleToRedis(
            hotArticleList, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + adChannel.getId());

        //
      }
    }
    cacheArticleToRedis(hotArticleVos, ArticleConstants.DEFAULT_TAG + ArticleConstants.DEFAULT_TAG);
  }
  /*

  缓存文章到redis中
   */
  private void cacheArticleToRedis(List<HotArticleVo> hotArticleList, String key) {
    // 对文章进行排序
    List<HotArticleVo> collect =
        hotArticleList.stream()
            .sorted(Comparator.comparing(HotArticleVo::getScore).reversed())
            .collect(Collectors.toList());
    // 放入到缓存中
    redisTemplate.opsForValue().set(key, JSON.toJSONString(collect));
  }
  /**
   * 计算文章的分值
   *
   * @param apArticles
   * @return
   */
  private List<HotArticleVo> computeArticleScore(List<ApArticle> apArticles) {

    List<HotArticleVo> hotArticleVoList =
        apArticles.stream()
            .map(
                apArticle -> {
                  HotArticleVo hotArticleVo = new HotArticleVo();
                  BeanUtils.copyProperties(apArticle, hotArticleVo);
                  // 计算分值设置到vo中
                  Integer score = computeScore(apArticle);
                  hotArticleVo.setScore(score);
                  return hotArticleVo;
                })
            .collect(Collectors.toList());

    return hotArticleVoList;
  }

  private Integer computeScore(ApArticle apArticle) {

    Integer score = 0;

    if (apArticle.getViews() != null) {
      score += apArticle.getViews() * ArticleConstants.HOT_ARTICLE_VIEW_WEIGHT;
    }
    if (apArticle.getLikes() != null) {
      score += apArticle.getLikes() * ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
    }
    if (apArticle.getComment() != null) {
      score += apArticle.getComment() * ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
    }
    if (apArticle.getCollection() != null) {
      score += apArticle.getComment() * ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
    }
    return score;
  }
}
